package com.gitee.wsl.ext.string

import kotlin.math.abs


/**
 * Hash算法大全<br></br>
 * 推荐使用FNV1算法
 *
 * @author Goodzzp, Looly
 */
object HashUtil {
    /**
     * 加法hash
     *
     * @param key   字符串
     * @param prime 一个质数
     * @return hash结果
     */
    fun additiveHash(key: String, prime: Int): Int {
        var hash: Int
        var i: Int
        hash = key.length
        i = 0
        while (i < key.length) {
            hash += key.get(i).code
            i++
        }
        return hash % prime
    }

    /**
     * 旋转hash
     *
     * @param key   输入字符串
     * @param prime 质数
     * @return hash值
     */
    fun rotatingHash(key: String, prime: Int): Int {
        var hash: Int
        var i: Int
        hash = key.length
        i = 0
        while (i < key.length) {
            hash = (hash shl 4) xor (hash shr 28) xor key.get(i).code
            ++i
        }

        // 使用：hash = (hash ^ (hash>>10) ^ (hash>>20)) & mask;
        // 替代：hash %= prime;
        // return (hash ^ (hash>>10) ^ (hash>>20));
        return hash % prime
    }

    /**
     * 一次一个hash
     *
     * @param key 输入字符串
     * @return 输出hash值
     */
    fun oneByOneHash(key: String): Int {
        var hash: Int
        var i: Int
        hash = 0
        i = 0
        while (i < key.length) {
            hash += key.get(i).code
            hash += (hash shl 10)
            hash = hash xor (hash shr 6)
            ++i
        }
        hash += (hash shl 3)
        hash = hash xor (hash shr 11)
        hash += (hash shl 15)
        // return (hash & M_MASK);
        return hash
    }

    /**
     * Bernstein's hash
     *
     * @param key 输入字节数组
     * @return 结果hash
     */
    fun bernstein(key: String): Int {
        var hash = 0
        var i: Int
        i = 0
        while (i < key.length) {
            hash = 33 * hash + key.get(i).code
            ++i
        }
        return hash
    }

    /**
     * Universal Hashing
     *
     * @param key  字节数组
     * @param mask 掩码
     * @param tab  tab
     * @return hash值
     */
    fun universal(key: CharArray, mask: Int, tab: IntArray): Int {
        var hash = key.size
        var i: Int
        val len = key.size
        i = 0
        while (i < (len shl 3)) {
            val k = key[i shr 3]
            if ((k.code and 0x01) == 0) {
                hash = hash xor tab[i]
            }
            if ((k.code and 0x02) == 0) {
                hash = hash xor tab[i + 1]
            }
            if ((k.code and 0x04) == 0) {
                hash = hash xor tab[i + 2]
            }
            if ((k.code and 0x08) == 0) {
                hash = hash xor tab[i + 3]
            }
            if ((k.code and 0x10) == 0) {
                hash = hash xor tab[i + 4]
            }
            if ((k.code and 0x20) == 0) {
                hash = hash xor tab[i + 5]
            }
            if ((k.code and 0x40) == 0) {
                hash = hash xor tab[i + 6]
            }
            if ((k.code and 0x80) == 0) {
                hash = hash xor tab[i + 7]
            }
            i += 8
        }
        return (hash and mask)
    }

    /**
     * Zobrist Hashing
     *
     * @param key  字节数组
     * @param mask 掩码
     * @param tab  tab
     * @return hash值
     */
    fun zobrist(key: CharArray, mask: Int, tab: Array<IntArray?>): Int {
        var hash: Int
        var i: Int
        hash = key.size
        i = 0
        while (i < key.size) {
            hash = hash xor tab[i]!![key[i].code]
            ++i
        }
        return (hash and mask)
    }

    /**
     * 改进的32位FNV算法1
     *
     * @param data 数组
     * @return hash结果
     */
    fun fnvHash(data: ByteArray): Int {
        val p = 16777619
        var hash = 2166136261L.toInt()
        for (b in data) {
            hash = (hash xor b.toInt()) * p
        }
        hash += hash shl 13
        hash = hash xor (hash shr 7)
        hash += hash shl 3
        hash = hash xor (hash shr 17)
        hash += hash shl 5
        return abs(hash)
    }

    /**
     * 改进的32位FNV算法1
     *
     * @param data 字符串
     * @return hash结果
     */
    fun fnvHash(data: String): Int {
        val p = 16777619
        var hash = 2166136261L.toInt()
        for (i in 0..<data.length) {
            hash = (hash xor data.get(i).code) * p
        }
        hash += hash shl 13
        hash = hash xor (hash shr 7)
        hash += hash shl 3
        hash = hash xor (hash shr 17)
        hash += hash shl 5
        return abs(hash)
    }

    /**
     * Thomas Wang的算法，整数hash
     *
     * @param key 整数
     * @return hash值
     */
    fun intHash(key: Int): Int {
        var key = key
        key += (key shl 15).inv()
        key = key xor (key ushr 10)
        key += (key shl 3)
        key = key xor (key ushr 6)
        key += (key shl 11).inv()
        key = key xor (key ushr 16)
        return key
    }

    /**
     * RS算法hash
     *
     * @param str 字符串
     * @return hash值
     */
    fun rsHash(str: String): Int {
        val b = 378551
        var a = 63689
        var hash = 0

        for (i in 0..<str.length) {
            hash = hash * a + str.get(i).code
            a = a * b
        }

        return hash and 0x7FFFFFFF
    }

    /**
     * JS算法
     *
     * @param str 字符串
     * @return hash值
     */
    fun jsHash(str: String): Int {
        var hash = 1315423911

        for (i in 0..<str.length) {
            hash = hash xor ((hash shl 5) + str.get(i).code + (hash shr 2))
        }

        return abs(hash) and 0x7FFFFFFF
    }

    /**
     * PJW算法
     *
     * @param str 字符串
     * @return hash值
     */
    fun pjwHash(str: String): Int {
        val bitsInUnsignedInt = 32
        val threeQuarters = (bitsInUnsignedInt * 3) / 4
        val oneEighth = bitsInUnsignedInt / 8
        val highBits = -0x1 shl (bitsInUnsignedInt - oneEighth)
        var hash = 0
        var test: Int

        for (i in 0..<str.length) {
            hash = (hash shl oneEighth) + str.get(i).code

            if (((hash and highBits).also { test = it }) != 0) {
                hash = ((hash xor (test shr threeQuarters)) and (highBits.inv()))
            }
        }

        return hash and 0x7FFFFFFF
    }

    /**
     * ELF算法
     *
     * @param str 字符串
     * @return hash值
     */
    fun elfHash(str: String): Int {
        var hash = 0
        var x: Int

        for (i in 0..<str.length) {
            hash = (hash shl 4) + str.get(i).code
            if (((hash.toLong() and 0xF0000000L).toInt().also { x = it }) != 0) {
                hash = hash xor (x shr 24)
                hash = hash and x.inv()
            }
        }

        return hash and 0x7FFFFFFF
    }

    /**
     * BKDR算法
     *
     * @param str 字符串
     * @return hash值
     */
    fun bkdrHash(str: String): Int {
        val seed = 131 // 31 131 1313 13131 131313 etc..
        var hash = 0

        for (i in 0..<str.length) {
            hash = (hash * seed) + str.get(i).code
        }

        return hash and 0x7FFFFFFF
    }

    /**
     * SDBM算法
     *
     * @param str 字符串
     * @return hash值
     */
    fun sdbmHash(str: String): Int {
        var hash = 0

        for (i in 0..<str.length) {
            hash = str.get(i).code + (hash shl 6) + (hash shl 16) - hash
        }

        return hash and 0x7FFFFFFF
    }

    /**
     * DJB算法
     *
     * @param str 字符串
     * @return hash值
     */
    fun djbHash(str: String): Int {
        var hash = 5381

        for (i in 0..<str.length) {
            hash = ((hash shl 5) + hash) + str.get(i).code
        }

        return hash and 0x7FFFFFFF
    }

    /**
     * DEK算法
     *
     * @param str 字符串
     * @return hash值
     */
    fun dekHash(str: String): Int {
        var hash = str.length

        for (i in 0..<str.length) {
            hash = ((hash shl 5) xor (hash shr 27)) xor str.get(i).code
        }

        return hash and 0x7FFFFFFF
    }

    /**
     * AP算法
     *
     * @param str 字符串
     * @return hash值
     */
    fun apHash(str: String): Int {
        var hash = 0

        for (i in 0..<str.length) {
            hash =
                hash xor if ((i and 1) == 0) ((hash shl 7) xor str.get(i).code xor (hash shr 3)) else (((hash shl 11) xor str.get(
                    i
                ).code xor (hash shr 5)).inv())
        }

        // return (hash & 0x7FFFFFFF);
        return hash
    }

    /**
     * TianL Hash算法
     *
     * @param str 字符串
     * @return Hash值
     */
    fun tianlHash(str: String): Long {
        var hash: Long

        val iLength = str.length
        if (iLength == 0) {
            return 0
        }

        if (iLength <= 256) {
            hash = 16777216L * (iLength - 1)
        } else {
            hash = 4278190080L
        }

        var i: Int

        var ucChar: Char

        if (iLength <= 96) {
            i = 1
            while (i <= iLength) {
                ucChar = str.get(i - 1)
                if (ucChar <= 'Z' && ucChar >= 'A') {
                    ucChar = (ucChar.code + 32).toChar()
                }
                hash += (3L * i * ucChar.code.toLong() * ucChar.code.toLong() + 5L * i * ucChar.code.toLong() + 7L * i + 11 * ucChar.code) % 16777216
                i++
            }
        } else {
            i = 1
            while (i <= 96) {
                ucChar = str.get(i + iLength - 96 - 1)
                if (ucChar <= 'Z' && ucChar >= 'A') {
                    ucChar = (ucChar.code + 32).toChar()
                }
                hash += (3L * i * ucChar.code.toLong() * ucChar.code.toLong() + 5L * i * ucChar.code.toLong() + 7L * i + 11 * ucChar.code) % 16777216
                i++
            }
        }
        if (hash < 0) {
            hash *= -1
        }
        return hash
    }

    /**
     * JAVA自己带的算法
     *
     * @param str 字符串
     * @return hash值
     */
    fun javaDefaultHash(str: String): Int {
        var h = 0
        var off = 0
        val len = str.length
        for (i in 0..<len) {
            h = 31 * h + str[off++].code
        }
        return h
    }

    /**
     * 混合hash算法，输出64位的值
     *
     * @param str 字符串
     * @return hash值
     */
    fun mixHash(str: String): Long {
        var hash = str.hashCode().toLong()
        hash = hash shl 32
        hash = hash or fnvHash(str).toLong()
        return hash
    }

    /**
     * HF Hash算法
     *
     * @param data 字符串
     * @return hash结果
     * @since 5.8.0
     */
    fun hfHash(data: String): Long {
        val length = data.length
        var hash: Long = 0

        for (i in 0..<length) {
            hash += data.get(i).code.toLong() * 3 * i
        }

        if (hash < 0) {
            hash = -hash
        }

        return hash
    }

    /**
     * HFIP Hash算法
     *
     * @param data 字符串
     * @return hash结果
     * @since 5.8.0
     */
    fun hfIpHash(data: String): Long {
        val length = data.length
        var hash: Long = 0
        for (i in 0..<length) {
            hash += (data.get(i % 4).code xor data.get(i).code).toLong()
        }
        return hash
    }
}